﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using TFhisto.UI.Controls.QueryEditorControl;

namespace TFhisto.UI
{
    /// <summary>
    /// Interaction logic for WorkItemHistory.xaml
    /// </summary>
    public partial class WorkItemHistory : UserControl
    {
        #region Fields
        private string SelectedTeamProjectName
        {
            get
            {
                if (cboProjects == null) return null;
                return cboProjects.Text;
            }
        }
        #endregion

        #region Class Scoped Values
        /// <summary>
        /// Stores the selected link types
        /// </summary>
        private List<TempLinkType> _selectedLinks;

        /// <summary>
        /// Stores the work items that back the list view for
        /// processing
        /// </summary>
        private List<WorkItemData> _queryResults;

        /// <summary>
        /// The query that it is currently being displayed on the results pane
        /// </summary>
        string _currentQuery = null;
        #endregion

        #region constructor
        public WorkItemHistory()
        {
            InitializeComponent();
            tFSUserControl1.LoadRegisteredServers();
            tFSUserControl1.PropertyChanged += new PropertyChangedEventHandler(tFSUserControl1_PropertyChanged);
            CommonUIHelper.Helper.PropertyChanged +=new PropertyChangedEventHandler(Helper_PropertyChanged);
            txtOutput.Text = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\Output.dgml";
        }
        #endregion
        
        #region Loading of TFS Server Connexions and list of Team Projects
        private void tFSUserControl1_PropertyChanged(Object sender, PropertyChangedEventArgs args)
        {
            if (args.PropertyName.Equals("TeamProjects"))
            {
                CommonUIHelper.Helper.AllowQueryEdition = true;
                cboProjects.ItemsSource = tFSUserControl1.TeamProjects;
                cboProjects.IsEnabled = true;
            }
        }
        #endregion 

        #region Processing management
        private void Helper_PropertyChanged(Object sender, PropertyChangedEventArgs args)
        {
            if (args.PropertyName.Equals("StatusMessage"))
            {
                ((StatusBarItem)statusBar.Items[0]).Content = CommonUIHelper.Helper.StatusMessage;
            }
            else if (args.PropertyName.Equals("AllowQueryEdition"))
            {
                btnEditQuery.IsEnabled = CommonUIHelper.Helper.AllowQueryEdition;
            }
        }
        #endregion 

        #region Select a project and Load Treeview and List
        /// <summary>
        /// Populate the list of work item queries for the selected team project
        /// **Special thanks to Jim Lamb for his code to help do this easily**
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSelectProject_Click(object sender, RoutedEventArgs e)
        {
            List<TreeNode> nodes = new List<TreeNode>();

            //Clear the contents of the treeview
            tvwQueries.ItemsSource = null;

            if (string.IsNullOrEmpty(SelectedTeamProjectName))
            {
                MessageBox.Show("Please select a team project");

                return;
            }

            //Loading the list of WorkItem Queries
            tvwQueries.ItemTemplate = (DataTemplate)this.FindResource("TreeNodeX");
            tvwQueries.ItemsSource = CommonUIHelper.LoadWITQueries(SelectedTeamProjectName);

            //Loading the list of WorkItem Links
            _selectedLinks = CommonUIHelper.LoadLinkTypes(SelectedTeamProjectName);
            lstLinkTypes.ItemsSource = _selectedLinks;

            CommonUIHelper.Helper.AllowQueryEdition = true;
        }
        #endregion

        #region Run Query
        /// <summary>
        /// Runs a given query and displays the result in the corresponding pane.
        /// </summary>
        /// <param name="query"></param>
        private void RunQuery(string wiql)
        {
            Query query = null;
            _queryResults = CommonUIHelper.RunQuery(wiql, SelectedTeamProjectName, out query);
            LoadListView(_queryResults, query);
        }

        /// <summary>
        /// Loads the listview with work items returned by the query
        /// </summary>
        /// <param name="wic">The collection of work items</param>
        /// <param name="q">The query that produced these work items</param>
        private void LoadListView(List<WorkItemData> wic, Query q)
        {
            //Set the data source of the grid to be the work item collection
            lstResults.ItemsSource = wic;

            //Clear the columns that are already in the grid
            GridView g = (GridView)lstResults.View;

            g.Columns.Clear();

            System.Windows.Controls.GridViewColumn selection = new System.Windows.Controls.GridViewColumn();
            selection.CellTemplate = (DataTemplate)this.FindResource("SelectionColumn");
            g.Columns.Add(selection);

            //For each of the columns specified as a display column for the query, bind a 
            //new column
            for (int i = 0; i < q.DisplayFieldList.Count; i++)
            {
                //Create the new text column
                System.Windows.Controls.GridViewColumn c = new System.Windows.Controls.GridViewColumn();

                //Set the header to the display field name
                c.Header = q.DisplayFieldList[i].Name;

                //Create a new binding with the path to the value that is being bound
                Binding b;
                if (q.DisplayFieldList[i].Name != "Title")
                    b = new Binding("WI.Fields[" + q.DisplayFieldList[i].Name + "].Value");
                else
                    b = new Binding("Title");
                b.Mode = BindingMode.OneTime;
                c.DisplayMemberBinding = b;

                //Set the binding and add the column
                g.Columns.Add(c);
            }
        }

        /// <summary>
        /// Event that is called when the user selected the run query option on the editor
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void queryEditor_QueryRun(object sender, QueryRunEventArgs e)
        {
            _currentQuery = e.WIQL;
            RunQuery(e.WIQL);
        }
        #endregion

        #region Button Clicks
        /// <summary>
        /// Allows the user to select the output file for the generated DGML
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnBrowse_Click(object sender, RoutedEventArgs e)
        {
            txtOutput.Text = CommonUIHelper.SetOutputFileName("Output.dgml");
        }

        /// <summary>
        /// Creates the state transition graph in DGML
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnState_Click(object sender, RoutedEventArgs e)
        {
            string groupByFieldName;

            groupByFieldName = ((System.Windows.Input.ICommandSource)sender).CommandParameter as string;

            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                WorkItem[] workItem = CommonUIHelper.GetSelectedWorkItems(this._queryResults);
                if (workItem == null || workItem.Length == 0)
                {
                    MessageBox.Show("To run a state visualization, select a single work item first.");
                }
                else
                {
                    ProcessStateDGML data = new ProcessStateDGML();

                    data.ProcessStates(workItem[0], txtOutput.Text, groupByFieldName);
                }
            }
            catch (UnauthorizedAccessException ex)
            {
                MessageBox.Show(ex.Message, "Unauthorized Access Exception");
            }
            finally
            {
                Mouse.OverrideCursor = null;
            }
        }

         //<summary>
         //Create the work item graph in DGML
         //</summary>
         //<param name="sender"></param>
         //<param name="e"></param>
        private void btnWorkItems_Click(object sender, RoutedEventArgs e)
        {
            string groupByFieldName;
            Mouse.OverrideCursor = Cursors.Wait;

            groupByFieldName = ((System.Windows.Input.ICommandSource)sender).CommandParameter as string;

            try
            {
                //Check to see if a project is even selected, if not, skip everything else
                if (String.IsNullOrEmpty(SelectedTeamProjectName))
                {
                    MessageBox.Show("Select a Team Project before trying to process any relationships.");
                }
                else if (CommonUIHelper.IsCurrentlyProcessing())
                {
                    MessageBox.Show("A process is already running, please wait and retry later.");
                }
                else
                {
                    CommonUIHelper.LaunchWorkItemAnalysis(ProcessCheckbox(chkFull)
                        , ProcessCheckbox(chkDependencyAnalysis)
                        , ProcessCheckbox(chkHideInterveningLinks)
                        , ProcessCheckbox(chkShowDeletedLinks)
                        , SelectedTeamProjectName
                        , txtOutput.Text
                        , this._queryResults
                        , _selectedLinks
                        , groupByFieldName);
                }
            }
            catch (UnauthorizedAccessException ex)
            {
                MessageBox.Show(ex.Message, "Unauthorized Access Exception");
            }
            finally
            {
                Mouse.OverrideCursor = null;
            }
        }

        /// <summary>
        /// Indicates whether or not the checkbox is checked
        /// </summary>
        /// <param name="box">The checkbox to process</param>
        /// <returns>True if it is checked or false if it is not</returns>
        private bool ProcessCheckbox(CheckBox box)
        {
            if ((box.IsChecked != null) && (box.IsChecked == true))
                return true;
            else
                return false;
        }

        #region Dependency Analysis
        //Process the dependency analysis checkbox and the related changeset checkbox
        //which must be checked
        private void chkDependencyAnalysis_Checked(object sender, RoutedEventArgs e)
        {
            ProcessDependencyAnalysisCheckbox();
            UpdateWorkItemsAllowedOperationsButton();
        }

        private void chkDependencyAnalysis_Unchecked(object sender, RoutedEventArgs e)
        {
            ProcessDependencyAnalysisCheckbox();
            UpdateWorkItemsAllowedOperationsButton();
        }

        /// <summary>
        /// Performs a number of operations based on whether a dependency analysis
        /// will be performed or not
        /// </summary>
        private void ProcessDependencyAnalysisCheckbox()
        {
            bool isChecked = ProcessCheckbox(chkDependencyAnalysis);

            //Check to see if the link types have been loaded. If they haven't it means
            //that the user hasn't select a team project yet.
            if (lstLinkTypes.Items.Count > 0)
            {
                //Find the underlying link type for a changesest
                TempLinkType result = _selectedLinks.Find(
                    delegate(TempLinkType s)
                    {
                        return s.LinkType == "Changesets";
                    }
                );

                //Set the underlying link type to checked  if the dependency
                //analysis is selected and disable it so the user can't uncheck it
                result.Selected = isChecked;
                result.Enabled = !isChecked;

                //*****NOT READY TO BE IMPLEMENTED YET*******
                //If it is checked, show the hide intervening links checkbox
                //if (isChecked)
                //{
                //    chkHideInterveningLinks.Visibility = System.Windows.Visibility.Visible;
                //}
                //else
                //{
                //    //Otherwise, hide it and uncheck it
                //    chkHideInterveningLinks.Visibility = System.Windows.Visibility.Hidden;
                //    chkHideInterveningLinks.IsChecked = false;
                //}

                //Refresh the links so they pick up the underlying data changes
                lstLinkTypes.Items.Refresh();
            }
            else
            {
                //This if is in here to handle the situation where the user could uncheck the dependency
                //analysis checkbox and the method is still triggered
                if (isChecked)
                {
                    MessageBox.Show("Please select a Team Project first.", "No Team Project Selected", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                    chkDependencyAnalysis.IsChecked = false;
                }
            }
        }
        #endregion

        /// <summary>
        /// Event when the user double clicks on a query
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tvwQueries_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            Mouse.OverrideCursor = Cursors.Wait;
            tabControl1.SelectedValue = tabControl1.Items[1];

            if (((TreeNode)tvwQueries.SelectedItem).Tag != null)
            {
                TreeNode item = (TreeNode)tvwQueries.SelectedItem;

                if (item.Tag.GetType() == typeof(QueryDefinition))
                {
                    _queryResults = new List<WorkItemData>();
                    QueryDefinition qd = (QueryDefinition)item.Tag;
                    _currentQuery = qd.QueryText;
                    RunQuery(_currentQuery);
                }
            }
            Mouse.OverrideCursor = null;
        }

        private void lstResults_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            WorkItemWindow wiWindow;
            wiWindow = new WorkItemWindow(((WorkItemData)lstResults.SelectedItem).WI);
            wiWindow.Show();
        }

        private void chkFull_Changed(object sender, RoutedEventArgs e)
        {
            UpdateWorkItemsAllowedOperationsButton();
        }

        private void chkLinkTypes_Changed(object sender, RoutedEventArgs e)
        {
            UpdateWorkItemsAllowedOperationsButton();
        }

        /// <summary>
        /// Updates the state of the work items operation split button so it reflects the options that the user can 
        /// perform based on other choices.
        ///
        /// The user can only group IF no full analysis is being performed, or a dependency analysis is going to be performed
        /// or if changesets are going to placed in the diagram
        /// 
        /// </summary>
        private void UpdateWorkItemsAllowedOperationsButton()
        {
            if (_selectedLinks != null)
            {
                foreach (TempLinkType selectedType in _selectedLinks)
                {
                    if (selectedType.LinkType == CommonUIHelper.ChangeSetLinkType && selectedType.Selected == true)
                    {
                        splitBtnWorkItem.Mode = Wpf.Controls.SplitButtonMode.Button;

                        return;
                    }
                }
            }

            if (chkDependencyAnalysis.IsChecked.Value == true || chkFull.IsChecked.Value == true)
            {
                splitBtnWorkItem.Mode = Wpf.Controls.SplitButtonMode.Button;
            }
            else
            {
                splitBtnWorkItem.Mode = Wpf.Controls.SplitButtonMode.Split;
            }
        }

        /// <summary>
        /// Launch the option editor dialog
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOptions_Click(object sender, RoutedEventArgs e)
        {
            Options o = new Options();
            o.Left = SystemParameters.PrimaryScreenWidth / 2 - o.Width / 2;
            o.Top = SystemParameters.PrimaryScreenHeight / 2 - o.Height / 2;

            o.ShowDialog();
        }

        /// <summary>
        /// Event that is called when the user selected the edit query.
        /// 
        /// This will pop up the query editor.
        /// 
        /// If a query has been executed it will allow you to change that query (but the change IS NOT persisted) 
        /// and rerun it at will.
        /// 
        /// If no query has been executed you can write an ad-hoc query from scratch and execute it.
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnEditQuery_Click(object sender, RoutedEventArgs e)
        {
            QueryEditor queryEditor;

            if (_currentQuery == null)
            {
                queryEditor = new QueryEditor(CommonUIHelper.Helper._wis, SelectedTeamProjectName);
            }
            else
            {
                queryEditor = new QueryEditor(CommonUIHelper.Helper._wis, SelectedTeamProjectName, _currentQuery);
            }

            queryEditor.CloseOnRun = true; // automatically close the window when run is executed
            queryEditor.QueryRun += new QueryEditor.QueryRunHandler(queryEditor_QueryRun);

            queryEditor.ShowDialog();
            queryEditor.Close();
        }
        #endregion
    }
}
